﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using ConsoleApplication2;
using Game1942.Library;
using Game1942.Library.Controller;
using Game1942.Library.Items;
using Game1942.Library.Planes;
using Game1942.Library.Provider;
using Game1942.Library.View;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Plane = Game1942.Library.Planes.Plane;
using Point = Game1942.Library.Background.Point;

namespace Game1942
{
    public class Game : State
    {
        #region [ Attributes ]
        
        protected Algo42Controller algo42Controller;  //Pongo el controlador del algo42
       
        protected KeyboardState previousKeyboardState;
        protected KeyboardState keyboardState;
        protected Driver driver;
        protected PlayerView playerView;
        protected BackgroundView backgroundView;
        protected BackgroundView cloudsView;
        protected EnergyView energyView;
        protected ScoreView scoreView;
        protected WeaponCounterView weaponCounterView;
        protected LifeView lifeView;

        protected Provider<Algo42> algo42Provider;
        protected Provider<int> scoreProvider;

        protected Music music;
        protected Song gameplayMusic;
        protected SoundEffect fireSound;
        private bool loadState;

        private GuidePlane aaa;

        #endregion

        #region [ Constructor ]
        public Game(GameContext screen, ContentManager contentManager, GraphicsDevice graphicsDevice, bool loadState)
        {
            this.screen = screen;
            content = contentManager;
            this.graphicsDevice = graphicsDevice;
            this.loadState = loadState;
            Initialize();
            LoadContent();
        }
        #endregion

        #region [ Initialize ]
        protected void Initialize()
        {
            //Instantiate a MODEL objects
            Driver.Clear();
            driver = Driver.Instance;//instancio el driver
            driver.SetContentManager(content);//Le paso el content manager
            driver.StartGame();

            if (loadState)
            {
                LoadPlayer();
            }

            backgroundView = new BackgroundView(graphicsDevice.Viewport.Height, graphicsDevice.Viewport.Height, 5);
            cloudsView = new BackgroundView(graphicsDevice.Viewport.Height, graphicsDevice.Viewport.Height, 20);
            scoreView = new ScoreView(graphicsDevice.Viewport.Width / 2, 10);
            energyView = new EnergyView(17, graphicsDevice.Viewport.Height - 30);
            playerView = new PlayerView(driver.Player.ActualPosition);      //Here
            weaponCounterView = new WeaponCounterView(graphicsDevice.Viewport.Width, graphicsDevice.Viewport.Height);
            lifeView = new LifeView(20,20);

            //Instantiate a CONTROLLER objects
            algo42Controller = new Algo42Controller(driver.Player, playerView);
         

            //Instantiate a PROVIDER objects
            algo42Provider = new Provider<Algo42>();
            scoreProvider = new Provider<int>();
            
        
            driver.viewList.Add(playerView);
           
            //Subscribe the views to the list of observers of the provider model
            energyView.Subscribe(algo42Provider);
            weaponCounterView.Subscribe(algo42Provider);
            scoreView.Subscribe(scoreProvider);
            lifeView.Subscribe(algo42Provider);
            
            //Instantiate the music gameplay
            music = new Music();
        }
        #endregion

        #region [ LoadContent ]
        protected void LoadContent()
        {
            //planeView.LoadContent(content.Load<Texture2D>("Planes/Plane"));
            

            backgroundView.TextureLoad(content.Load<Texture2D>("Backgrounds/Sea"));
            cloudsView.TextureLoad(content.Load<Texture2D>("Backgrounds/Cloud"));
            energyView.LoadContent(content.Load<Texture2D>("Energy/box"), content.Load<Texture2D>("Energy/energybar"),
                content.Load<SpriteFont>("Fonts/Energy"));
            scoreView.LoadContent(content.Load<SpriteFont>("Fonts/Score"));
            playerView.LoadContent(content.Load<Texture2D>("Planes/FA-18A"), content.Load<Texture2D>("Planes/FA-18A-Right"), content.Load<Texture2D>("Planes/FA-18A-Left"));
            weaponCounterView.LoadContent(content.Load<SpriteFont>("Fonts/Weapons"));
            lifeView.LoadContent(content.Load<Texture2D>("Life/Life"), content.Load<SpriteFont>("Fonts/Life"));

            // Load the music and sound effects
            gameplayMusic = content.Load<Song>("Sounds/GameMusic");
            algo42Controller.SetFireSound(content.Load<SoundEffect>("Sounds/LaserFire"));
            // Start the music right away
            music.PlayMusic(gameplayMusic);
        }
        #endregion

        #region [ Update ]
        public override void Update(GameTime gameTime)
        {
            // Allows the game to exit
            if ((GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) || driver.EndGame())
                screen.Exit();
            //Actualizo las imagenes del background
            backgroundView.UpdatePosition();
            cloudsView.UpdatePosition();

            //Capturo el estado actual del teclado
            keyboardState = Keyboard.GetState();

            if(keyboardState.IsKeyDown(Keys.Escape))
            {
                screen.State = new MainMenu(screen, content, graphicsDevice);
            }

            //Le decimos al controlador que agarre las teclas presionadas y que modifique el modelo
            algo42Controller.KeyPressed(keyboardState, previousKeyboardState);

            //Guardo el estado actual para no disparar una rafaga
            previousKeyboardState = keyboardState;
            
            //Hago jugar a los objetos del modelo
            driver.Play();

            if (driver.IsLevelFinished())
            {
                driver = Driver.Instance;
                driver.SetContentManager(content);
                driver.viewList.Add(playerView);
                //Update(gameTime);
            }
           
            //Actualizo las vistas)
            for (int i = 0; i < driver.providerList.Count; i++)
            {
                driver.providerList[i].NotifyObservers(driver.computerList[i]);
            }
            
            //Filtro la lista de los objetos del modelo para que saque a los que estan muertos
            driver.RemoveDeadUnits();
            //Filtro la lista de vistas para sacar los que estan muertos y las desinscribo de su proveedor
            driver.RemoveNotVisibleViews();
            //Filtro la lista de proveedores para sacar aquellos que no poseen observers
            driver.RemoveEmptyProviders();
            algo42Provider.NotifyObservers(driver.Player);
            scoreProvider.NotifyObservers(driver.Score);
            
        }
        #endregion

        #region [ Draw ]

        public override void Draw(GameTime gameTime)
        {
            graphicsDevice.Clear(Color.CornflowerBlue);

            screen.SpriteBatchField.Begin();
            //******    Begin Drawing     ******//

            backgroundView.Draw(screen.SpriteBatchField);

            foreach (var view in driver.viewList)
            {
                view.Draw(screen.SpriteBatchField);
            }
            cloudsView.Draw(screen.SpriteBatchField);
            energyView.Draw(screen.SpriteBatchField);

            scoreView.Draw(screen.SpriteBatchField);

            weaponCounterView.Draw(screen.SpriteBatchField);

            lifeView.Draw(screen.SpriteBatchField);
            //******    End Drawing     ******//
            screen.SpriteBatchField.End();
        }
        #endregion

        #region [ Other Methods ]

        //Load´s a player state at the last save game
        private void LoadPlayer()
        {
            try
            {
                var serialize = new Serialize<SaveUnit>();
                var saveGame = serialize.DeserializeGame(Directory.GetCurrentDirectory() + "\\save.xml");

                var a = new Algo42();
                a.SetPosition(new Point(saveGame.xPos, saveGame.yPos));
                driver.Player = a;

                driver.Player.Energy = saveGame.energy;
                driver.Player.AmountOfRockets = saveGame.amountOfRockets;
                driver.Player.AmountOfTorpedos = saveGame.amountOfTorpedos;
                driver.Score = saveGame.score;
                driver.Player.Lifes = saveGame.lifes;
                
                
            }
            catch (Exception)
            {
            }
        }

        #endregion

    }
}
